# https://gitee.com/yueyinqiu5990/tj12413601/blob/master/assignment1/question2/main_integration.py
import math
import os.path
from typing import TextIO

import matplotlib.pyplot

import calculators.gauss_legendre_method
import calculators.simpsons_method
import calculators.trapezoidal_method
from integration_calculator import Integration1dCalculatorAdaptive
from integration_problem import IntegrationProblem1d


def _integrate_and_output(
        title: str,
        subplot: int,
        markdown: TextIO,
        problem: IntegrationProblem1d,
        calculator: Integration1dCalculatorAdaptive,
        end_condition: float,
        analytical_result: float,
        scatter_arguments: dict):
    print(f"正在使用{title}求积分，可能需要一定的时间……")

    matplotlib.pyplot.subplot(subplot)
    matplotlib.pyplot.title(title)
    matplotlib.pyplot.xlabel("迭代次数")
    matplotlib.pyplot.ylabel("结果")
    matplotlib.pyplot.tight_layout(h_pad=2)
    axh_line = matplotlib.pyplot.axhline(analytical_result)

    markdown.write(f"{title}：\n\n")
    markdown.write("|迭代次数|当前结果|与分析值的差异|\n")
    markdown.write("|:-:|:-:|:-:|\n")

    scatter: matplotlib.pyplot.PathCollection | None = None
    steps = calculator.calculate_with_steps(problem, end_condition, 5)
    for i, step in enumerate(steps):
        d = step - analytical_result
        markdown.write(f"|{i}|{step:.6f}|{d:.3e} ({d / analytical_result * 100 :.2f}%)|\n")
        scatter = matplotlib.pyplot.scatter(i, step, **scatter_arguments)

    markdown.write("\n")
    assert scatter is not None
    matplotlib.pyplot.legend([axh_line, scatter], ["analytical", "numerical"])


def _main():
    output_directory = os.path.abspath("./outputs")

    matplotlib.pyplot.rcParams['font.sans-serif'] = ['SimHei']
    matplotlib.pyplot.rcParams['axes.unicode_minus'] = False
    matplotlib.pyplot.figure(figsize=(8, 8), dpi=200)

    problem1 = IntegrationProblem1d(lambda x: x ** 2, 0, 1)
    problem2 = IntegrationProblem1d(math.sqrt, 0, 1)
    with open(os.path.join(output_directory, "output.md"),
              "w", encoding="utf8") as markdown:
        _integrate_and_output(
            "变步长梯形法",
            221, markdown,
            problem1,
            calculators.trapezoidal_method.TrapezoidalMethod(),
            2e-4, 1 / 3,
            {"c": "red", "marker": "o", "s": 1})
        _integrate_and_output(
            "辛普森法",
            222, markdown,
            problem2,
            calculators.simpsons_method.SimpsonsMethod(),
            1e-6, 2 / 3,
            {"c": "red", "marker": "o", "s": 3})
        _integrate_and_output(
            "高斯勒让德法（一）",
            223, markdown,
            problem1,
            calculators.gauss_legendre_method.GaussLegendreMethod(),
            10, 1 / 3,
            {"c": "red", "marker": "o", "s": 20})
        _integrate_and_output(
            "高斯勒让德法（二）",
            224, markdown,
            problem2,
            calculators.gauss_legendre_method.GaussLegendreMethod(),
            10, 2 / 3,
            {"c": "red", "marker": "o", "s": 20})
    print("正在生成图像……")
    matplotlib.pyplot.savefig(os.path.join(output_directory, "output.png"))
    print(f"运行完成，结果已保存在 {output_directory}")


if __name__ == "__main__":
    _main()
